/*
	file:   gentask.c
	author: Anders Ma
	email:  xuejiao.ma@gmail.com
	date:   2010_1114
*/

#include "gentask.h"


static int depth;
static class_t *class_head = NULL;
static NODE_TYPE curr_node;

void* MALLOC(int size)
{
	void *p = malloc(size);
	memset(p, 0, size);
#ifdef DEBUG_MEM
	PRINT("MALLOC -> %x\n", p);
#endif
	return p;
}

void FREE(void *ptr)
{
	free(ptr);
#ifdef DEBUG_MEM
	PRINT("FREE <- %x\n", ptr);
#endif
}

#ifdef _WIN32
int
utf8_to_unicode(char* in, char *out)
{
	int len = strlen(in);
	int i, j, k;

	for (i = 0, j = 0, k = 0; i < len; j += 2) {
		if (((in[i] >> 3) & 0x1E) == 0x1E) {
			// 11110xxx
			// don't know how to convert it to 16bits unicode, tbd??
		} else if (((in[i] >> 4) & 0x0E) == 0x0E) {
			// 1110xxxx
			out[j] = ((in[i + 1] & 0x03) << 6) + (in[i + 2] & 0x3F);
			out[j + 1] = ((in[i] & 0x0F) << 4) + ((in[i + 1] >> 2) & 0x0F);
			i += 3;
		} else if (((in[i] >> 5) & 0x07) == 0x06) {
			// 110xxxxx
			out[j] = (in[i] >> 2) & 0x07;
			out[j + 1] = ((in[i] & 0x03) << 6) + (in[i + 1] & 0x3F);
			i += 2;				
		} else if (((in[i] >> 7) & 0x01) == 0) {
			//0xxxxxxx <ASCII>
			out[j] = in[i];
			out[j + 1] = 0X00;
			i += 1;
		}
		k += 1;
	}

	return k;
}

int
convert_charset(char *in, char *out, int len)
{
	char unicode_buf[MAX_BUFLINE_SIZE];
	int unicode_size, multi_size;

	unicode_size = utf8_to_unicode(in, unicode_buf);
	multi_size = WideCharToMultiByte(CP_ACP, NULL, &unicode_buf, 
					 unicode_size ,out,
					 len, NULL, NULL);

	return multi_size;
}

char *
strndup(const char *str, int len)
{
	char in[MAX_BUFLINE_SIZE];
	char out[MAX_BUFLINE_SIZE];
	int size;
	char *p;
	
	memcpy(in, str, len);
	*(in + len) = '\0';
	size = convert_charset(in, out, MAX_BUFLINE_SIZE);
	p = (char*)MALLOC(sizeof(char)*(size + 1));
	if (p != NULL) {
		memcpy(p, out, size);
		*(p + size) = '\0';
	}
	return p;
}
#endif

static void XMLCALL
start (void *data, const char *el, const char **attr)
{

	int i;
	char *n = NULL;
	void *p = NULL;
	void *q = NULL;

	curr_node = UNKNOWN_NODE;

#if 0
	for (i = 0; i < depth; i++)
		PRINT ("  ");

	PRINT("%s", el);
#endif
	if (!strcmp(el, "class")) {
		curr_node = CLASS_NODE;
		for (i = 0; attr[i]; i += 2) {
			if (!strcmp(attr[i], "name")) {
				n = (char*)attr[i+1];
				break;
			}
			//PRINT(" %s='%s'", attr[i], attr[i + 1]);
		}
		p = MALLOC(sizeof(class_t));
		if (!p) {
			fprintf(stderr, "Couldn't allocate memory for class\n");
			return;
		}
		q = (void*)class_head;
		class_head = (class_t*)p;
#ifdef _WIN32
		class_head->name = strndup(n, strlen(n));
#else
		class_head->name = strdup(n);
#endif
		class_head->next = (class_t*)q;

	} else if (!strcmp(el, "item")) {
		curr_node = ITEM_NODE;
		for (i = 0; attr[i]; i += 2) {
			//PRINT(" %s='%s'", attr[i], attr[i + 1]);
		}
		p = MALLOC(sizeof(item_t));
		if (!p) {
			fprintf(stderr, "Couldn't allocate memory for item\n");
			return;
		}
		q = (void*)class_head->item;
		class_head->item = (item_t*)p;
		class_head->item->next = (item_t*)q;
	}
	depth++;

}

static void XMLCALL
end (void *data, const char *el)
{
	depth--;
}

static void XMLCALL
data(void *data, const char *cont, int len)
{
	int i = 0;

#if 0
	PRINT("  ");
	while(i < len) {
		PRINT("%c", *(cont + i));
		i++;
	}
#endif
	if (curr_node == ITEM_NODE) {
			if (!class_head->item->name)
				class_head->item->name = strndup(cont, len);
	}
}

static void
clean()
{
	class_t *c, *cn;
	item_t *i, *in;
	int m, n;

	for (m = 1, c = class_head; c != NULL;) {
		PRINT("%d %s\n", m, c->name);
		cn = c->next;
		for (n = 1, i = c->item; i != NULL;) {
			PRINT("\t%d.%d %s\n", m, n++, i->name);
			in = i->next;
			if (i->name)
				FREE(i->name);
			FREE(i);
			i = in;
		}
		FREE(c);
		c = cn;
		m++;
	}
}

#ifdef _WIN32
long int
get_random_number()
{
	int seed, rdm;

	seed = GetTickCount();
	srand(seed);    
	rdm = rand();
      
	return rdm;
}
#else
long int
get_random_number()
{
	unsigned int seed;
	struct timeval tv;
	long int rdm;

	gettimeofday (&tv, NULL);
	seed = tv.tv_sec + tv.tv_usec;
	srand(seed);	
	rdm = random();
	
	return rdm;
}
#endif

void
gentask(class_t * p)
{
	class_t *r;
	item_t *q;
	long int class, item;
	long int i, j;


	i = 0;
	r = p;
	while (p) {
		p = p->next;
		i++;
	}
	class = (i > 0) ? get_random_number() % i : -1;

	i = 0;
	p = r;
	while (p) {
		if (i++ == class) {
			q = p->item;
			j = 0;
			while (q) {
				j++;
				q = q->next;
			}
			break; 
		}
		p = p->next;
	}
	item = (j > 0) ? get_random_number() % j : -1;

	p = r;
	i = 0;
	while (p) {
		if (i++ == class) {
			q = p->item;
			j = 0;
			while (q) {
				if (j++ != item) {
					q = q->next;
					continue;
				}
				fprintf(stderr, "+-----------------------+\n");
				fprintf(stderr, "+ TASK \n");
				fprintf(stderr, "+ [%ld.%ld]%s\n", 
						        i, j, q->name);
				fprintf(stderr, "+-----------------------+\n");
				return;
			}
			break; 
		}
		p = p->next;
	}

}

int
main (int argc, char *argv[])
{
	FILE *fp;
	XML_Parser p;
	char buf[MAX_BUFLINE_SIZE];
	char *str;

	fp = fopen(TASK_FILE_NAME, "r");
	if (!fp) {
		fprintf(stderr, "Couldn't open task file\n");
		exit(-1);		
	}
	p = XML_ParserCreate(NULL);
	if (!p) {
		fprintf(stderr, "Couldn't allocate memory for XML parser\n");
		exit (-1);
	}
	XML_SetElementHandler (p, start, end);
	XML_SetCharacterDataHandler(p, data);
	
	for (;;) {
		int done;
		int len;

		str = fgets(buf, MAX_BUFLINE_SIZE, fp);
		len = strlen(buf);
		done = feof(fp);

		if (XML_Parse (p, buf, len, done) == XML_STATUS_ERROR) {
			fprintf(stderr, "Parse error at line %" 
					XML_FMT_INT_MOD "u:\n%s\n",
              				XML_GetCurrentLineNumber(p),
              				XML_ErrorString(XML_GetErrorCode(p)));
			clean();
			exit (-1);
		}

		if (done)
			break;
	}
	XML_ParserFree (p);
	gentask(class_head);
	clean();

#ifdef _WIN32
	fprintf(stderr, "\nplease press any key to escape ...\n");
	getch(stdin);
#endif
	return 0;
}
